/*
 * map.c
 *
 *  Created on: 15 nov. 2010
 *      Author: Nicolas Aucouturier, Laurent Reveillere, Vincent Filou
 */

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <SDL.h>
#include <SDL_image.h>

#include <time.h>
#include "../include/constant.h"
#include "../include/map.h"
#include "../include/misc.h"

#include "../include/game.h"

typedef char t_cell_type_;

struct s_map {
	int width;
	int height;

	t_cell_type_* grid;

	SDL_Surface* img_bomberwoman;
	SDL_Surface* img_box;
	SDL_Surface* img_goal;
	SDL_Surface* img_bonus_bomb_range_inc;
	SDL_Surface* img_bonus_bomb_range_dec;
	SDL_Surface* img_bonus_bomb_nb_inc;
	SDL_Surface* img_bonus_bomb_nb_dec;
	SDL_Surface* img_key;
	SDL_Surface* img_door;
	SDL_Surface* img_closed_door;
	SDL_Surface* img_stone;
	SDL_Surface* img_tree;
	SDL_Surface* img_bomb4;
	SDL_Surface* img_life;
};

#define CELL(i,j) (i +  map->width * j)

t_map map_new(int width, int height) {
	assert(width > 0 && height > 0);

	t_map map = malloc(sizeof (struct s_map));
	if (map == NULL )
		exit(EXIT_FAILURE);

	map->width = width;
	map->height = height;

	map->grid = (t_cell_type_ *) malloc(height * width * sizeof(t_cell_type_));
	if (map->grid == NULL )
		exit(EXIT_FAILURE);

	// Grid cleaning
	int i, j;
	for (i = 0; i < width; i++) {
		for (j = 0; j < height; j++) {
			map->grid[CELL(i,j)] = CELL_EMPTY;
		}
	}

	// Sprite loading
	map->img_tree =load_image(IMG_MAP_TREE);
	map->img_box = load_image(IMG_MAP_CASE);
	map->img_goal = load_image(IMG_MAP_GOAL);
	map->img_key = load_image(IMG_MAP_KEY);
	map->img_stone = load_image(IMG_MAP_STONE);
	map->img_door = load_image(IMG_MAP_DOOR);
	map->img_closed_door = load_image(IMG_MAP_CLOSED_DOOR);
	map->img_bomb4 = load_image(IMG_BOMB_TTL4);
	map->img_bonus_bomb_range_inc = load_image(IMG_BONUS_BOMB_RANGE_INC);
	map->img_bonus_bomb_range_dec = load_image(IMG_BONUS_BOMB_RANGE_DEC);
	map->img_bonus_bomb_nb_inc = load_image(IMG_BONUS_BOMB_NB_INC);
	map->img_bonus_bomb_nb_dec = load_image(IMG_BONUS_BOMB_NB_DEC);
	map->img_bomberwoman = load_image("sprite/bomberwoman.png");
	map->img_life = load_image(IMG_BANNER_LIFE);


	return map;
}


int map_is_inside(t_map map, int x, int y) {
	assert(map);
	if(map_get_width(map)-1<x || x<0 || y<0 || map_get_height(map)-1<y)
		return 0;
	else
		return 1;
}

void map_free(t_map map) {
	if (map == NULL ) {
		return;
	}

	free(map->grid);

	SDL_FreeSurface(map->img_bonus_bomb_nb_dec);
	SDL_FreeSurface(map->img_bonus_bomb_nb_inc);
	SDL_FreeSurface(map->img_bonus_bomb_range_dec);
	SDL_FreeSurface(map->img_bonus_bomb_range_inc);
	SDL_FreeSurface(map->img_closed_door);
	SDL_FreeSurface(map->img_door);
	SDL_FreeSurface(map->img_key);
	SDL_FreeSurface(map->img_stone);
	SDL_FreeSurface(map->img_box);
	SDL_FreeSurface(map->img_goal);
	SDL_FreeSurface(map->img_tree);

	free(map);
}

int map_get_width(t_map map) {
	assert(map != NULL);
	return map->width;
}

int map_get_height(t_map map) {
	assert(map != NULL);
	return map->height;
}

t_cell_type map_get_cell_type(t_map map, int x, int y) {
	assert(map && map_is_inside(map, x, y));
	return map->grid[CELL(x,y)] & 15;
}

t_cell_type map_get_cell_type2(t_map map, int x, int y) {
	assert(map && map_is_inside(map, x, y));
	return (map->grid[CELL(x,y)] >> 4 & 15);
}

void map_set_cell_type(t_map map, int x, int y, t_cell_type type) {
	assert(map && map_is_inside(map, x, y));
	map->grid[CELL(x,y)] = type;
}

void display_bonus(t_map map, SDL_Surface* screen, SDL_Rect* place,
		t_cell_type type) {
	// bonus is encoded with the 4 most significant bits
	switch (type >> 4) {
	case BONUS_BOMB_RANGE_INC:
		SDL_BlitSurface(map->img_bonus_bomb_range_inc, NULL, screen, place);
		break;

	case BONUS_BOMB_RANGE_DEC:
		SDL_BlitSurface(map->img_bonus_bomb_range_dec, NULL, screen, place);
		break;

	case BONUS_BOMB_NB_INC:
		SDL_BlitSurface(map->img_bonus_bomb_nb_inc, NULL, screen, place);
		break;

	case BONUS_BOMB_NB_DEC:
		SDL_BlitSurface(map->img_bonus_bomb_nb_dec, NULL, screen, place);
		break;
	case BONUS_LIFE:
		SDL_BlitSurface(map->img_life, NULL, screen, place);
		break;
	}
}

void display_scenery(t_map map, SDL_Surface* screen, SDL_Rect* place,
		t_cell_type type) {

	switch (type >> 4) {
	case SCENERY_STONE:
		SDL_BlitSurface(map->img_stone, NULL, screen, place);
		break;

	case SCENERY_TREE:
		SDL_BlitSurface(map->img_tree, NULL, screen, place);
		break;
	}
}

void display_door(t_map map, SDL_Surface* screen, SDL_Rect* place,
		t_cell_type type) {

	switch (type & 128) {
	case 0:
		SDL_BlitSurface(map->img_door, NULL, screen, place);
		break;
	case 128:
			SDL_BlitSurface(map->img_closed_door, NULL, screen, place);
			break;
	}
}

void map_display(t_map map, SDL_Surface *screen) {
	int i, j;

	assert(map != NULL);
	assert(screen != NULL);
	assert(map->height > 0 && map->width > 0);

	assert(map->img_bonus_bomb_nb_dec != NULL);
	assert(map->img_bonus_bomb_nb_inc != NULL);
	assert(map->img_bonus_bomb_range_dec != NULL);
	assert(map->img_bonus_bomb_range_inc != NULL);
	assert(map->img_closed_door != NULL);
	assert(map->img_door != NULL);
	assert(map->img_key != NULL);
	assert(map->img_stone != NULL);
	assert(map->img_box != NULL);
	assert(map->img_goal != NULL);
	assert(map->img_bomb4 != NULL);
  assert(map->img_bomberwoman != NULL);

	for (i = 0; i < map->width; i++) {
		for (j = 0; j < map->height; j++) {
			SDL_Rect place;
			place.x = i * SIZE_BLOC;
			place.y = j * SIZE_BLOC;

			t_cell_type_ type = map->grid[CELL(i,j)];

			switch (type & 15) { // type is encoded with 4 bits (the & 15 (1111)) is a mask to keep the four less significant bits)
			case CELL_GOAL:
				SDL_BlitSurface(map->img_goal, NULL, screen, &place);
				break;
			case CELL_SCENERY:
				display_scenery(map, screen, &place, type);
				break;
			case CELL_CASE:
				SDL_BlitSurface(map->img_box, NULL, screen, &place);
				break;
			case CELL_BONUS:
				display_bonus(map, screen, &place, type);
				break;
			case CELL_KEY:
				SDL_BlitSurface(map->img_key, NULL, screen, &place);
				break;
			case CELL_DOOR:
				display_door(map, screen, &place, type);
				//SDL_BlitSurface(map->img_door, NULL, screen, &place);
				break;

			case CELL_BOMBERWOMAN:
				SDL_BlitSurface(map->img_bomberwoman, NULL, screen, &place);
				break;
			}
		}

	}
}

//Remove the bomb on the map when we quit it
t_map map_get_bomb_removed(t_map map)
{

	for (int i = 0; i < map_get_height(map)*map_get_height(map); i++) {
			if(map->grid[i] == CELL_BOMB)
				map->grid[i]=CELL_EMPTY;
		}
	return map;


}

//get the state of the door (open or close) given by the most significant bit
t_cell_type map_get_door_state(t_map map, int x, int y) {
	assert(map && map_is_inside(map, x, y));
	return (map->grid[CELL(x,y)] & 128);
}

//get the number of the map behind the door
t_cell_type map_get_door_numb(t_map map, int x, int y) {
	assert(map && map_is_inside(map, x, y));
	return (map->grid[CELL(x,y)] >> 4 & 7);
}

t_map map_get_current(int num_level,int num_map){

	//We create a new map and we read the file to fill in this map
	int x,y,read;
	int i,j;
	if(num_level==0){
		if(num_map==0){
		FILE* file=fopen("map/map_1_1.map","r");
		fscanf(file,"%d,%d\n",&x,&y);
		t_map map_r=map_new(x,y);

		t_cell_type the_map_r[x*y];
		for(i=0;i<x;i++)
		{
			for(j=0;j<y;j++)
			{
				fscanf(file,"%d",&read);
				the_map_r[i*x+j]=(char) read;
			}
			fscanf(file,"\n");
		}
		for(int j=0;j<x*y;j++)
			{
				map_r->grid[j]=the_map_r[j];
			}
			return map_r;
			fclose(file);
			}


		if(num_map==1){
		FILE* file=fopen("map/map_2_1.map","r");
		fscanf(file,"%d,%d\n",&x,&y);
		t_map map_r=map_new(x,y);

		t_cell_type the_map_r[x*y];
		for(i=0;i<x;i++)
		{
			for(j=0;j<y;j++)
			{
				fscanf(file,"%d",&read);
				the_map_r[i*x+j]=(char) read;
			}
			fscanf(file,"\n");
		}
		for(int j=0;j<x*y;j++)
		{
			map_r->grid[j]=the_map_r[j];
		}
		return map_r;
		fclose(file);
		}



	if(num_map==2)
		{
			FILE* file=fopen("map/map_3_1.map","r");
			fscanf(file,"%d,%d\n",&x,&y);
			t_map map_r=map_new(x,y);
			t_cell_type the_map_r[x*y];
			for(i=0;i<x;i++)
				{
					for(j=0;j<y;j++)
					{
						fscanf(file,"%d",&read);
						the_map_r[i*x+j]=(char) read;
					}
					fscanf(file,"\n");
				}
			for(int j=0;j<x*y;j++)
				{
					map_r->grid[j]=the_map_r[j];
				}
				return map_r;
				fclose(file);
				}
	}

if(num_level==1){
	if(num_map==0)
		{
				FILE* file=fopen("map/map_1_2.map","r");
				fscanf(file,"%d,%d\n",&x,&y);
				t_map map_r=map_new(x,y);
				t_cell_type the_map_r[x*y];
				for(i=0;i<x;i++)
				{
					for(j=0;j<y;j++)
					{
						fscanf(file,"%d",&read);
						the_map_r[i*x+j]=(char) read;
					}
					fscanf(file,"\n");
				}
				for(int j=0;j<x*y;j++)
					{
						map_r->grid[j]=the_map_r[j];
					}
					return map_r;
					fclose(file);
					}

	if(num_map==1)
			{
					FILE* file=fopen("map/map_2_2.map","r");
					fscanf(file,"%d,%d\n",&x,&y);
					t_map map_r=map_new(x,y);
					t_cell_type the_map_r[x*y];
					for(i=0;i<x;i++)
					{
						for(j=0;j<y;j++)
						{
							fscanf(file,"%d",&read);
							the_map_r[i*x+j]=(char) read;
						}
						fscanf(file,"\n");
					}
					for(int j=0;j<x*y;j++)
						{
							map_r->grid[j]=the_map_r[j];
						}
						return map_r;
						fclose(file);
						}

	if(num_map==2)
				{
						FILE* file=fopen("map/map_3_2.map","r");
						fscanf(file,"%d,%d\n",&x,&y);
						t_map map_r=map_new(x,y);
						t_cell_type the_map_r[x*y];
						for(i=0;i<x;i++)
						{
							for(j=0;j<y;j++)
							{
								fscanf(file,"%d",&read);
								the_map_r[i*x+j]=(char) read;
							}
							fscanf(file,"\n");
						}
						for(int j=0;j<x*y;j++)
							{
								map_r->grid[j]=the_map_r[j];
							}
							return map_r;
							fclose(file);
							}

}
if(num_level==2){
	if(num_map==0)
		{
				FILE* file=fopen("map/map_1_3.map","r");
				fscanf(file,"%d,%d\n",&x,&y);
				t_map map_r=map_new(x,y);
				t_cell_type the_map_r[x*y];
				for(i=0;i<x;i++)
				{
					for(j=0;j<y;j++)
					{
						fscanf(file,"%d",&read);
						the_map_r[i*x+j]=(char) read;
					}
					fscanf(file,"\n");
				}
				for(int j=0;j<x*y;j++)
					{
						map_r->grid[j]=the_map_r[j];
					}
					return map_r;
					fclose(file);
					}
	if(num_map==1)
			{
					FILE* file=fopen("map/map_2_3.map","r");
					fscanf(file,"%d,%d\n",&x,&y);
					t_map map_r=map_new(x,y);
					t_cell_type the_map_r[x*y];
					for(i=0;i<x;i++)
					{
						for(j=0;j<y;j++)
						{
							fscanf(file,"%d",&read);
							the_map_r[i*x+j]=(char) read;
						}
						fscanf(file,"\n");
					}
					for(int j=0;j<x*y;j++)
						{
							map_r->grid[j]=the_map_r[j];
						}
						return map_r;
						fclose(file);
						}
	if(num_map==2)
			{
					FILE* file=fopen("map/map_3_3.map","r");
					fscanf(file,"%d,%d\n",&x,&y);
					t_map map_r=map_new(x,y);
					t_cell_type the_map_r[x*y];
					for(i=0;i<x;i++)
					{
						for(j=0;j<y;j++)
						{
							fscanf(file,"%d",&read);
							the_map_r[i*x+j]=(char) read;
						}
						fscanf(file,"\n");
					}
					for(int j=0;j<x*y;j++)
						{
							map_r->grid[j]=the_map_r[j];
						}
						return map_r;
						fclose(file);
						}
}
if(num_level==3){
	if(num_map==0)
		{
				FILE* file=fopen("map/end.map","r");
				fscanf(file,"%d,%d\n",&x,&y);
				t_map map_r=map_new(x,y);
				t_cell_type the_map_r[x*y];
				for(i=0;i<x;i++)
				{
					for(j=0;j<y;j++)
					{
						fscanf(file,"%d",&read);
						the_map_r[i*x+j]=(char) read;
					}
					fscanf(file,"\n");
				}
				for(int j=0;j<x*y;j++)
					{
						map_r->grid[j]=the_map_r[j];
					}
					return map_r;
					fclose(file);
					}
}


		return 0;
}

t_map map_set_bonus(t_map map) {
	for (int i = 0; i < map_get_height(map)*map_get_width(map); i++) {
		if(map->grid[i] == CELL_CASE) {
			int bonus_yn=rand()%10; //Y aura t-il un bonus ?
			if (bonus_yn <=7) { //Bonus
				int bonus_type=rand()%10; //Quel type de bonus ?
				if (bonus_type == 0){ //bonus bomb range
					int bomb_range=rand()%10;//Quel bonus ?
					if (bomb_range<=4){ // bomb range inc
						map->grid[i]=CELL_CASE_RANGEINC;
					}
					else {//bomb range dec
						map->grid[i]=CELL_CASE_RANGEDEC;
					}

				}
				else if (bonus_type>=4 && bonus_type<=7) {//Bonus bomb nb
					int bomb_nb=rand()%10;
					if (bomb_nb<=2){//bomb nb inc
						map->grid[i]=CELL_CASE_BOMBINC;
					}
					else { //bomb nb dec
						map->grid[i]=CELL_CASE_BOMBDEC;
					}
				}
				else if (bonus_type == 8) {//Bonus monstre
					map->grid[i]=CELL_CASE_MONSTER;
				}
				else if (bonus_type == 9) {//Bonus vie
					map->grid[i]=CELL_CASE_LIFE;
								}
			}
			else { //Pas de bonus
				map->grid[i]=CELL_CASE;
			}

		}
	}
	return map;

}
